/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.webapp.taglib.core.grid.util;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * <p>Represents sort field in grid. Sort order may be ascending or descending. By default it is ascending.
 * </p>
 * <p><a href="SortField.java.html"><i>View Source</i></a></p>
 *
 * @author Sergey Zubtsovskiy <a href="mailto:sergey.zubtsovskiy@blandware.com">&lt;sergey.zubtsovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.10 $ $Date: 2006/08/03 10:08:22 $
 */
public class SortField implements Serializable {

	// ~ Static variables

	/**
	 * Indicates that sort order is ascending
	 */
	public static final String ORDER_ASCENDING = "asc";

	/**
	 * Indicates that sort order is descending
	 */
	public static final String ORDER_DESCENDING = "desc";

	// ~ Instance variables

	/**
	 * Name of field to sort by
	 */
	protected String fieldName;

	/**
	 * Name of property to lookup value in order to compare entities, when collection is not taken from persistent storage
	 */
	protected String property;

	/**
	 * Sorting order (ascending or descending)
	 */
	protected String order = ORDER_ASCENDING;

	/**
	 * Has or has not been order changed between two subsequent calls to this instance
	 */
	protected boolean orderChanged = false;

	/**
	 * List of identifiers of rowIterators this sort field is applicable to
	 */
	protected List rowIterators = Collections.synchronizedList(new LinkedList());

	/**
	 * Creates new instance of SortField
	 *
	 * @param fieldName Name of field to sort by
	 */
	public SortField(String fieldName) {
		this(fieldName, ORDER_ASCENDING);
	}

	/**
	 * Creates new instance of SortField with given sort order
	 *
	 * @param fieldName Name of field to sort by
	 * @param order     Sorting order (ascending or descending)
	 */
	public SortField(String fieldName, String order) {
		this.fieldName = fieldName;
		if ( ORDER_ASCENDING.equalsIgnoreCase(order) ) {
			this.order = ORDER_ASCENDING;
		} else {
			this.order = ORDER_DESCENDING;
		}
	}

    /**
     * Returns name of field
     *
     * @return field name
     * @see #fieldName
     */
	public String getFieldName() {
		return fieldName;
	}

    /**
     * Sets name of field
     *
     * @param fieldName field name to set
     * @see #fieldName
     */
	public void setFieldName(String fieldName) {
		this.fieldName = fieldName;
	}

    /**
     * Returns property name
     *
     * @return property name
     * @see #property
     */
	public String getProperty() {
		return property;
	}

    /**
     * Sets property name
     *
     * @param property property name to set
     * @see #property
     */
	public void setProperty(String property) {
		this.property = property;
	}

    /**
     * Returns sort order
     *
     * @return sort order
     * @see #order
     */
	public String getOrder() {
		return order;
	}

    /**
     * Sets sort order
     *
     * @return sort order
     * @see #order
     */
	public List getRowIterators() {
		return rowIterators;
	}

    /**
     * Returns list of row iterators
     *
     * @param rowIterators row iterators list
     * @see #rowIterators
     */
	public void setRowIterators(List rowIterators) {
		this.rowIterators = rowIterators;
	}

    /**
     * Sets list of row iterators
     *
     * @param rowIteratorId row iterators list
     * @see #rowIterators
     */
	public void addRowIterator(String rowIteratorId) {
		this.rowIterators.add(rowIteratorId);
	}

	/**
	 * Gets part of ORDER BY clause
	 *
	 * @param rowIteratorId ID of row iterator
	 * @return part of ORDER BY clause corresponding to row iterator with
     * specified ID. If now iterator with such ID was found, <code>null</code>
	 */
	public String getClause(String rowIteratorId) {
		if ( (rowIteratorId == null) || (rowIterators.size() == 0) || (rowIterators.contains(rowIteratorId)) ) {
			return fieldName + " " + order;
		} else {
			return null;
		}
	}

	/**
	 * Returns <code>true</code> if order is ascending
	 *
	 * @return True if order is ascending and false, if descending
	 */
	public boolean isOrderAscending() {
		return order.equalsIgnoreCase(ORDER_ASCENDING);
	}

	/**
	 * Reverses order from ascending to descending and vice versa
	 */
	public void reverseOrder() {
		if ( order.equalsIgnoreCase(ORDER_ASCENDING) ) {
			order = ORDER_DESCENDING;
		} else {
			order = ORDER_ASCENDING;
		}
		orderChanged = true;
	}

	/**
	 * Returns <code>true</code> if order has been changed between two subsequent calls to this instance
     *
	 * @return <code>True</code> if order has been changed between two subsequent calls to this instance
	 */
	public boolean hasOrderChanged() {
		boolean orderChanged = this.orderChanged;

		// restore value, because on the next call we need correct information
		this.orderChanged = false;
		return orderChanged;
	}

	public String toString() {
		return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
	}

	/**
	 * Compares this instance with another object
	 *
	 * @param anObject Object to compare with
	 * @return True, if anObject is instance of SortField and has the same values of fieldName and order fields
	 *         in case insensitive manner. Otherwise, returns false;
	 */
	public boolean equals(Object anObject) {
		if ( anObject instanceof SortField ) {
			SortField sortField = (SortField) anObject;
			return (this.fieldName.equalsIgnoreCase(sortField.getFieldName())) && (this.order.equalsIgnoreCase(sortField.getOrder()));
		} else {
			return false;
		}
	}

	/**
	 * Returns hash code of this instance
	 *
	 * @return hash code
	 */
	public int hashCode() {
		int result;
		result = (fieldName != null ? fieldName.hashCode() : 0);
		result = 29 * result + (order != null ? order.hashCode() : 0);
		return result;
	}


}
